from abc import ABC, abstractmethod
from logging import Logger

from simpy import Environment

from util.dateutil import ts_date
from x_pc.model.model import TaskCtx


class Cargo(object):
    """
    货物
    """
    name: str = None

    def __init__(self, name: str = '货物'):
        self.name = name


class DeviceData(object):
    """
    设备数据
    """
    # 类别
    category: str = None


class Object(object):
    env: Environment = None
    # 名称
    name: str = None
    # 编码
    code: str = None

    def __init__(self, env: Environment, name: str, code: str = None):
        self.env = env
        self.name = name
        if code:
            self.code = code


class Device(Object, DeviceData, ABC):
    """
    设备 抽象类
    """

    def __init__(self, env: Environment, name: str):
        super().__init__(env, name)

    @staticmethod
    @abstractmethod
    def device_type() -> int:
        """
        设备类型
        :return:
        """
        pass

    @abstractmethod
    def device_code(self) -> str:
        """
        设备code
        :return:
        """
        pass

    @abstractmethod
    def loc(self) -> str:
        """
        设备 LOC位置信息
        :return:
        """
        pass


class DeviceCost(ABC):
    """
    设备耗时
    """

    @abstractmethod
    def cost(self, *args, **kwargs) -> float:
        pass


class DeviceCache(ABC):
    """
    设备缓存
    """

    @abstractmethod
    def cache_nums(self) -> int:
        pass


class System(Object):
    """
    系统 抽象类
    """
    # 待执行任务列表
    task_list: list[TaskCtx] = []
    # 系统辅助标识
    running = False

    logger: Logger | None = None

    def __init__(self, env: Environment, name: str, code: str = None):
        super().__init__(env, name, code)
        self.task_list = list()

    def run(self):
        """
        运行
        :return:
        """
        while self.running:
            if not self.task_list:
                # 会导致任务执行 实际开始时间延后
                yield self.env.timeout(1)
                continue
            task_ctx = self.choose_task()
            yield self.env.process(self.run_task(task_ctx))

    def choose_task(self) -> TaskCtx:
        """
        选择任务执行
        :return:
        """
        return self.task_list.pop(0)

    @abstractmethod
    def run_task(self, task_ctx: TaskCtx):
        """
        执行任务
        :param task_ctx:
        :return:
        """
        pass

    def push_task(self, task_ctx: TaskCtx):
        """
        接收外部推送的任务
        :param task_ctx:
        :return:
        """
        self.logger.info('[PC] PushTask -> %s, task: %s, time: %s', self.name, task_ctx.task.task_id, ts_date(self.env.now))
        self.task_list.append(task_ctx)

    def start(self):
        """
        系统启动
        :return:
        """
        if self.get_logger():
            msg = f'[PC] {self.name} 开始启动'
            self.get_logger().debug(msg)
        self.running = True
        self.env.process(self.run())

    def stop(self):
        """
        系统停止
        :return:
        """
        self.running = False
        if self.get_logger():
            msg = f'[PC] {self.name} 停止运动'
            self.get_logger().debug(msg)

    def get_logger(self) -> Logger | None:
        if not self.logger:
            if hasattr(self, 'sys_data'):
                sys_data = getattr(self, 'sys_data')
                if hasattr(sys_data, 'logger'):
                    self.logger = getattr(sys_data, 'logger')
        return self.logger
